feat: Add SeedsToTracks to Examples - #5845
Merged
Merged
Conversation
This was referenced Aug 7, 2026
Turns seeds into tracks with one track state per space-point source link, and stores the seed estimate on the innermost state. `addSeeding` built the `seed-tracks` through `SeedsToProtoTracks` and `ProtoTracksToTracks` so far. A proto track is a flat list of measurement indices, so that route loses the structure the seed carries and leaves two things resting on the order in which `seedToProtoTrack` happens to flatten the space points: which state is the innermost, and that the estimate of a seed still lines up with its proto track. `TrackParamsEstimationAlgorithm` expresses the estimate on the bottom space point's surface, which a seed names directly. The estimate is allocated once as predicted and shared as filtered and smoothed, since it is all that is known at that state. With a tracking geometry the track states also get their reference surface, which bound parameters on a state need to mean anything. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FxPc2jP43AQuQKz8c4qsaC
andiwand
force-pushed
the
seeds-to-tracks
branch
from
August 7, 2026 12:04
162149f to
e219c73
Compare
andiwand
marked this pull request as ready for review
August 7, 2026 12:11
Contributor
Public API surface diffNo change to the public API surface. ✅ |
Contributor
|
andiwand
added a commit
to andiwand/acts
that referenced
this pull request
Aug 17, 2026
Moves the track parameters of a track container onto a common surface, typically a perigee. That is what makes a seed estimate comparable to truth. The estimate sits on the bottom space point's sensor, where the truth reference has to be carried from the production vertex through the bending in between, so the comparison belongs on a perigee. Only the track-level parameters are moved. The states are shared with the input container rather than copied, so they keep the parameters on their own surfaces and the output has the same layering a fitter produces, without a second copy of the state backend. Tracks whose extrapolation fails are dropped, so any truth matching has to run downstream. `Acts::findTrackStateForExtrapolation` is fixed along with it, for tracks that carry parameters on only some of their states - every seed track from acts-project#5845, where only the bottom space point holds the estimate. `firstOrLast` intersects both ends unconditionally to compare their distances, and the helper only asserted that the state it intersects has smoothed or filtered parameters, so a release build read an unallocated parameter slot. A state without parameters now yields no intersection instead, so such a track extrapolates from the end that does carry them rather than being rejected. Used by acts-project#5721, nothing else in the repository calls it yet. ### Notes - `Acts::extrapolateTrackToReferenceSurface` is not called; its body is reproduced in the algorithm instead. The helper takes a single track proxy and does both halves through it: it reads the states off that proxy to pick the state to start from, and it writes the extrapolated parameters back onto it in place. Here the two cannot be the same proxy. - Reading has to happen on the input, which is a read-only `ConstTrackContainer` off the whiteboard. `parameters()` and `setReferenceSurface()` are `requires(!ReadOnly)`, so instantiating the helper on an input track does not compile. - Writing has to happen on the output track, which is mutable but whose container is paired with an empty `Acts::VectorMultiTrajectory`, because `Acts::TrackContainer` cannot pair a mutable track backend with a read-only state backend. The input state backend is only attached at the very end, when the const output container is built, so the tip and stem indices that `copyFromShallow` carries over do not resolve during the loop. Calling the helper on the output track would compile and then walk an empty backend. `Acts::findTrackStateForExtrapolation` and the `ForcedSurfaceReached` propagate call are used directly instead, which is the helper minus the write-back. An overload that separates the state source from the parameter destination, or one that returns the `BoundTrackParameters` rather than writing them, would let this call into Core; kept out of this PR. - On the second commit, which is the Core fix. It was raised in review on the first one, where the algorithm instead checked the precondition up front and dropped those tracks. - The fallback needs no new branching: the `firstOrLast` comparison already handles an invalid intersection, which carries an infinite path length and so loses to the other end. A seed track therefore extrapolates from its bottom space point under any strategy, and passing `first` in acts-project#5721 is an optimisation rather than a requirement. - `CompatibleTrackStateNotFound` is now reported when no end can be started from, as opposed to `ReferenceSurfaceUnreachable` when the ends do carry parameters but do not reach the surface. - The parameters come from `Acts::TrackStateProxy::parameters` rather than a second smoothed-over-filtered ladder, so the distance is measured on the same parameters that `createParametersFromState` starts the propagation from. That also admits a state holding only predicted parameters, which the old ladder rejected even though the propagation would have used them. - Behaviour is unchanged wherever every measurement state carries parameters, which covers both existing `firstOrLast` callers, `KalmanFitter` and `TrackFindingAlgorithm`. `findTrackStateForExtrapolation` had no unit test coverage at all; the new cases in `TrackHelpersTests` need no propagator and fail on the unpatched header. - `Acts::TrackProxy::copyFrom`, the deep copy, is not an alternative to sharing the states: it copies every state with a hardcoded `TrackStatePropMask::All`, which throws for a state that holds no parameters at all - every state of a seed track except the innermost. Passing `srcTrackState.getMask()` there would fix it, kept out of this PR. - `Acts::TrackExtrapolationStrategy` gets python bindings here. --------- Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
yannikaMatt
pushed a commit
to yannikaMatt/acts
that referenced
this pull request
Aug 21, 2026
Turns seeds into tracks with one track state per space-point source link, and stores the seed estimate on the innermost state. `addSeeding` built the `seed-tracks` through `SeedsToProtoTracks` and `ProtoTracksToTracks` so far. A proto track is a flat list of measurement indices, so that route drops the structure the seed carries and leaves two things resting on the order in which `seedToProtoTrack` happens to flatten the space points: which state is the innermost, and that the estimate of a seed still lines up with its proto track. `TrackParamsEstimationAlgorithm` expresses the estimate on the bottom space point's surface, which a seed names directly. The estimate is allocated once as predicted and shared as filtered and smoothed, since it is all that is known at that state. With a tracking geometry the track states also get their reference surface, which bound parameters on a state need in order to mean anything.
yannikaMatt
pushed a commit
to yannikaMatt/acts
that referenced
this pull request
Aug 21, 2026
Moves the track parameters of a track container onto a common surface, typically a perigee. That is what makes a seed estimate comparable to truth. The estimate sits on the bottom space point's sensor, where the truth reference has to be carried from the production vertex through the bending in between, so the comparison belongs on a perigee. Only the track-level parameters are moved. The states are shared with the input container rather than copied, so they keep the parameters on their own surfaces and the output has the same layering a fitter produces, without a second copy of the state backend. Tracks whose extrapolation fails are dropped, so any truth matching has to run downstream. `Acts::findTrackStateForExtrapolation` is fixed along with it, for tracks that carry parameters on only some of their states - every seed track from acts-project#5845, where only the bottom space point holds the estimate. `firstOrLast` intersects both ends unconditionally to compare their distances, and the helper only asserted that the state it intersects has smoothed or filtered parameters, so a release build read an unallocated parameter slot. A state without parameters now yields no intersection instead, so such a track extrapolates from the end that does carry them rather than being rejected. Used by acts-project#5721, nothing else in the repository calls it yet. ### Notes - `Acts::extrapolateTrackToReferenceSurface` is not called; its body is reproduced in the algorithm instead. The helper takes a single track proxy and does both halves through it: it reads the states off that proxy to pick the state to start from, and it writes the extrapolated parameters back onto it in place. Here the two cannot be the same proxy. - Reading has to happen on the input, which is a read-only `ConstTrackContainer` off the whiteboard. `parameters()` and `setReferenceSurface()` are `requires(!ReadOnly)`, so instantiating the helper on an input track does not compile. - Writing has to happen on the output track, which is mutable but whose container is paired with an empty `Acts::VectorMultiTrajectory`, because `Acts::TrackContainer` cannot pair a mutable track backend with a read-only state backend. The input state backend is only attached at the very end, when the const output container is built, so the tip and stem indices that `copyFromShallow` carries over do not resolve during the loop. Calling the helper on the output track would compile and then walk an empty backend. `Acts::findTrackStateForExtrapolation` and the `ForcedSurfaceReached` propagate call are used directly instead, which is the helper minus the write-back. An overload that separates the state source from the parameter destination, or one that returns the `BoundTrackParameters` rather than writing them, would let this call into Core; kept out of this PR. - On the second commit, which is the Core fix. It was raised in review on the first one, where the algorithm instead checked the precondition up front and dropped those tracks. - The fallback needs no new branching: the `firstOrLast` comparison already handles an invalid intersection, which carries an infinite path length and so loses to the other end. A seed track therefore extrapolates from its bottom space point under any strategy, and passing `first` in acts-project#5721 is an optimisation rather than a requirement. - `CompatibleTrackStateNotFound` is now reported when no end can be started from, as opposed to `ReferenceSurfaceUnreachable` when the ends do carry parameters but do not reach the surface. - The parameters come from `Acts::TrackStateProxy::parameters` rather than a second smoothed-over-filtered ladder, so the distance is measured on the same parameters that `createParametersFromState` starts the propagation from. That also admits a state holding only predicted parameters, which the old ladder rejected even though the propagation would have used them. - Behaviour is unchanged wherever every measurement state carries parameters, which covers both existing `firstOrLast` callers, `KalmanFitter` and `TrackFindingAlgorithm`. `findTrackStateForExtrapolation` had no unit test coverage at all; the new cases in `TrackHelpersTests` need no propagator and fail on the unpatched header. - `Acts::TrackProxy::copyFrom`, the deep copy, is not an alternative to sharing the states: it copies every state with a hardcoded `TrackStatePropMask::All`, which throws for a state that holds no parameters at all - every state of a seed track except the innermost. Passing `srcTrackState.getMask()` there would fix it, kept out of this PR. - `Acts::TrackExtrapolationStrategy` gets python bindings here. --------- Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
yannikaMatt
pushed a commit
to yannikaMatt/acts
that referenced
this pull request
Aug 21, 2026
Turns seeds into tracks with one track state per space-point source link, and stores the seed estimate on the innermost state. `addSeeding` built the `seed-tracks` through `SeedsToProtoTracks` and `ProtoTracksToTracks` so far. A proto track is a flat list of measurement indices, so that route drops the structure the seed carries and leaves two things resting on the order in which `seedToProtoTrack` happens to flatten the space points: which state is the innermost, and that the estimate of a seed still lines up with its proto track. `TrackParamsEstimationAlgorithm` expresses the estimate on the bottom space point's surface, which a seed names directly. The estimate is allocated once as predicted and shared as filtered and smoothed, since it is all that is known at that state. With a tracking geometry the track states also get their reference surface, which bound parameters on a state need in order to mean anything.
yannikaMatt
pushed a commit
to yannikaMatt/acts
that referenced
this pull request
Aug 21, 2026
Moves the track parameters of a track container onto a common surface, typically a perigee. That is what makes a seed estimate comparable to truth. The estimate sits on the bottom space point's sensor, where the truth reference has to be carried from the production vertex through the bending in between, so the comparison belongs on a perigee. Only the track-level parameters are moved. The states are shared with the input container rather than copied, so they keep the parameters on their own surfaces and the output has the same layering a fitter produces, without a second copy of the state backend. Tracks whose extrapolation fails are dropped, so any truth matching has to run downstream. `Acts::findTrackStateForExtrapolation` is fixed along with it, for tracks that carry parameters on only some of their states - every seed track from acts-project#5845, where only the bottom space point holds the estimate. `firstOrLast` intersects both ends unconditionally to compare their distances, and the helper only asserted that the state it intersects has smoothed or filtered parameters, so a release build read an unallocated parameter slot. A state without parameters now yields no intersection instead, so such a track extrapolates from the end that does carry them rather than being rejected. Used by acts-project#5721, nothing else in the repository calls it yet. ### Notes - `Acts::extrapolateTrackToReferenceSurface` is not called; its body is reproduced in the algorithm instead. The helper takes a single track proxy and does both halves through it: it reads the states off that proxy to pick the state to start from, and it writes the extrapolated parameters back onto it in place. Here the two cannot be the same proxy. - Reading has to happen on the input, which is a read-only `ConstTrackContainer` off the whiteboard. `parameters()` and `setReferenceSurface()` are `requires(!ReadOnly)`, so instantiating the helper on an input track does not compile. - Writing has to happen on the output track, which is mutable but whose container is paired with an empty `Acts::VectorMultiTrajectory`, because `Acts::TrackContainer` cannot pair a mutable track backend with a read-only state backend. The input state backend is only attached at the very end, when the const output container is built, so the tip and stem indices that `copyFromShallow` carries over do not resolve during the loop. Calling the helper on the output track would compile and then walk an empty backend. `Acts::findTrackStateForExtrapolation` and the `ForcedSurfaceReached` propagate call are used directly instead, which is the helper minus the write-back. An overload that separates the state source from the parameter destination, or one that returns the `BoundTrackParameters` rather than writing them, would let this call into Core; kept out of this PR. - On the second commit, which is the Core fix. It was raised in review on the first one, where the algorithm instead checked the precondition up front and dropped those tracks. - The fallback needs no new branching: the `firstOrLast` comparison already handles an invalid intersection, which carries an infinite path length and so loses to the other end. A seed track therefore extrapolates from its bottom space point under any strategy, and passing `first` in acts-project#5721 is an optimisation rather than a requirement. - `CompatibleTrackStateNotFound` is now reported when no end can be started from, as opposed to `ReferenceSurfaceUnreachable` when the ends do carry parameters but do not reach the surface. - The parameters come from `Acts::TrackStateProxy::parameters` rather than a second smoothed-over-filtered ladder, so the distance is measured on the same parameters that `createParametersFromState` starts the propagation from. That also admits a state holding only predicted parameters, which the old ladder rejected even though the propagation would have used them. - Behaviour is unchanged wherever every measurement state carries parameters, which covers both existing `firstOrLast` callers, `KalmanFitter` and `TrackFindingAlgorithm`. `findTrackStateForExtrapolation` had no unit test coverage at all; the new cases in `TrackHelpersTests` need no propagator and fail on the unpatched header. - `Acts::TrackProxy::copyFrom`, the deep copy, is not an alternative to sharing the states: it copies every state with a hardcoded `TrackStatePropMask::All`, which throws for a state that holds no parameters at all - every state of a seed track except the innermost. Passing `srcTrackState.getMask()` there would fix it, kept out of this PR. - `Acts::TrackExtrapolationStrategy` gets python bindings here. --------- Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.



Turns seeds into tracks with one track state per space-point source link, and
stores the seed estimate on the innermost state.
addSeedingbuilt theseed-tracksthroughSeedsToProtoTracksandProtoTracksToTracksso far. A proto track is a flat list of measurementindices, so that route drops the structure the seed carries and leaves two
things resting on the order in which
seedToProtoTrackhappens to flatten thespace points: which state is the innermost, and that the estimate of a seed
still lines up with its proto track.
TrackParamsEstimationAlgorithmexpressesthe estimate on the bottom space point's surface, which a seed names directly.
The estimate is allocated once as predicted and shared as filtered and
smoothed, since it is all that is known at that state.
With a tracking geometry the track states also get their reference surface,
which bound parameters on a state need in order to mean anything.
--- END COMMIT MESSAGE ---
First of four. Review order:
SeedsToTracksTrackExtrapolationAlgorithmaddSeeding1 to 3 are independent of each other, 4 needs all of them. All of them target
main, so the diff of 4 contains 1 to 3 until they merge. #5846 is a small fixfound along the way and is independent of all of these.
SeedsToProtoTracksstays, the proto tracks are still written byaddSeedPerformanceWriters.Validation
The
seed-trackscome out identical to theProtoTracksToTracksroute:seedToProtoTrackwalksseed.spacePoints()andsp.sourceLinks()in thesame nested order, so the states, their order, their source links and
nMeasurementsall match. Measured through #5721 on 100 particle-gun events,the residual and pull histograms of the seed estimate agree to the last digit
between the two routes.
The python test suite gives the same set of failures as
mainon the samemachine.